package trim.calc.smdata;

import java.util.ArrayList;
import java.util.List;
import trim.common.RejectedZone;
import trim.common.inputdata.FormatOrder;
import trim.common.inputdata.InputData;
import trim.common.sm.SMColumn;
import trim.common.sm.SimpleTrimSMData;
import trim.common.utils.Utils;

/**
 * Создан 14.10.2009 16:45:50
 * @author Дмитрий
 */
public class StaticPatternsTrimSMData extends SimpleTrimSMData
{

  private List<int[]> patterns;

  public StaticPatternsTrimSMData(InputData inputData)
  {
    super(inputData);
    patterns=new ArrayList(1024);
    GenPatternData se=new GenPatternData();
    se.zones=material.getRejectedZones();
    se.zcount=se.zones.size();
    se.formatLengths=new int[n];
    int i=0;
    for(FormatOrder fo:this.inputData.getFormatOrderList())
      se.formatLengths[i++]=fo.getFormat().getLength();
    se.knifeCount=material.getKnifeCount();
    se.formatCount=n;
    //int S=material.getLength()-material.getMinEdge()*2;
    se.effectiveWidth=S;
    se.knifeInterval=material.getKnifeInterval();
    int lam;//небракованный остаток тамбура
    int xx[]=new int[n], xx1[]=new int[n];//решения
    int Sort[]=new int[n];//массив индексов(для сортировки по возрастанию)
    se.currentPattern=xx;
    se.bestPattern=xx1;
    //se.sort=Sort;
    se.m=n;
    if(se.zcount==0)
    {
      lam=0;
      genColumns(se,S,0,0,lam,0,0);
    }else
    {
      lam=S;
      for(RejectedZone rz:se.zones)
        lam-=Math.max(rz.getWidth(),se.knifeInterval);
      lam-=se.zones.get(0).getStart();
      genColumns(se,se.zones.get(0).getStart(),0,0,lam,0,0);
    }
    System.out.println("Pattern count - "+patterns.size());
  }

  @Override
  public SMColumn getBestColumn(double[] dualVars)
  {
    double rec=Double.MIN_VALUE;
    int r=-1;
    int q=0;
    for(int[] p:patterns)
    {
      double est=0;
      for(int i=0;i<n;i++)
        est+=p[i]*dualVars[i];
      if(rec<est)
      {
        rec=est;
        r=q;
      }
      q++;
    }
    double[] res=new double[n];
    int[] w=patterns.get(r);
    for(int i=0;i<n;i++)
      res[i]=w[i];
    return new SMColumn(rec-1,res);
  }

  private void genColumns(GenPatternData se,
    int zactiveWidth,int zusedWidth,int zactive,int lam,int count,int cf)
  {
    if(cf>0&&lam>=0)
    {
      addColumn(se.currentPattern);
    }

    for(int i=cf;i<se.m;i++)
    {
      if(se.formatLengths[i]>zactiveWidth)
        continue;

      int t=(int)(zactiveWidth/se.formatLengths[i]);
      if((count+t)>=se.knifeCount)
        t=se.knifeCount-1-count;
      while(t>0)
      {
        se.currentPattern[i]+=t;
        genColumns(se,zactiveWidth-t*se.formatLengths[i],
          zusedWidth+t*se.formatLengths[i],
          zactive,
          lam,
          count+t,i+1);
        se.currentPattern[i]-=t;
        t--;
      }
    }
    if(zactive==se.zcount)
      return;

    RejectedZone z=se.zones.get(zactive);
    zusedWidth=Math.max(z.getWidth()+z.getStart(),zusedWidth+se.knifeInterval);
    zactive++;

    if(zactive==se.zcount)
    {
      zactiveWidth=se.effectiveWidth-zusedWidth;
      lam=0;
    }else
    {
      z=se.zones.get(zactive);
      zactiveWidth=z.getStart()-zusedWidth;
      lam-=z.getStart()-se.zones.get(zactive-1).getStart()-se.zones.get(zactive-1).getWidth();
    }

    genColumns(se,zactiveWidth,zusedWidth,zactive,lam,count,0);
  }

  private void addColumn(int[] d)
  {
    int[] x=new int[n];
    System.arraycopy(d,0,x,0,n);
    patterns.add(x);
  }

  private static class GenPatternData
  {

    double rec=Double.MIN_NORMAL;
    List<RejectedZone> zones;
    int zcount;
    int knifeInterval;
    int m;
    //int sort[];
    int currentPattern[], bestPattern[];
    double dualVars[];
    int[] formatLengths;
    int formatCount;
    int knifeCount;
    int effectiveWidth;
  }
}
